/*MyPhotoIndex Free Photo Organizer <www.myphotoindex.com>
  Copyright (C) <2006-2009>  <Asaf Yarkoni asaf@yarkoni.net>

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing.Printing;
using System.Collections.ObjectModel;
using System.Drawing;
using MyPhotoIndex.Interfaces;
using MyPhotoIndex.Utilities;
using MyPhotoIndex.Interfaces.Imaging;

namespace MyPhotoIndex.Plugins.Printing
{
    internal class ImagePrinting : PrintDocument
    {
        ReadOnlyCollection<IImageData>  m_images;
        int                             m_imageCols = 2;
        int                             m_imageRows = 4;
        int                             m_imagesPerPage;
        int                             m_nextImage;
        PrintAction                     m_printAction;
        bool                            m_isLandscape;
        Size                            m_printSize;

        internal ImagePrinting(ReadOnlyCollection<IImageData> images, int imageCols, int imageRows, bool landscape):
        this(images, imageCols, imageRows, landscape, Size.Empty)
        {   
        }

        internal ImagePrinting(ReadOnlyCollection<IImageData> images, int imageCols, int imageRows, bool landscape, Size printSize)
        {
            m_images = images;

            m_imageCols = imageCols;
            m_imageRows = imageRows;
            m_imagesPerPage = m_imageCols * m_imageRows;

            m_isLandscape = landscape;
            m_printSize = printSize;
            base.BeginPrint += new PrintEventHandler(IamgePrinting_BeginPrint);
            base.PrintPage += new PrintPageEventHandler(IamgePrinting_PrintPage);
            base.QueryPageSettings += new QueryPageSettingsEventHandler(ImagePrinting_QueryPageSettings);
        }

        void ImagePrinting_QueryPageSettings(object sender, QueryPageSettingsEventArgs e)
        {
            e.PageSettings.Landscape = m_isLandscape;
        }

        void IamgePrinting_BeginPrint(object sender, PrintEventArgs e)
        {
            m_nextImage = 0;
            m_printAction = e.PrintAction;
        }

        void IamgePrinting_PrintPage(object sender, PrintPageEventArgs e)
        {
            Rectangle pageBounds = Rectangle.Ceiling(e.PageSettings.PrintableArea);
            if (e.PageSettings.Landscape == true &&
                pageBounds.Width < pageBounds.Height)
            {
                pageBounds = new Rectangle(pageBounds.Y, pageBounds.X, pageBounds.Height, pageBounds.Width);
            }

            int leftMarginWidth = 0;
            int topMargin = 0;
            if (m_printAction == PrintAction.PrintToPreview)
            {
                leftMarginWidth = (int)(pageBounds.Left * e.Graphics.DpiX / 100);
                topMargin = (int)(pageBounds.Top * e.Graphics.DpiX / 100);
            }

            int numOfImagesToPrint = Math.Min(m_images.Count - m_nextImage, m_imagesPerPage);
            IImageData[] imagesToPrint = new IImageData[numOfImagesToPrint];
            for (int ii = 0; ii < imagesToPrint.Length; ii++)
            {
                imagesToPrint[ii] = m_images[m_nextImage++];
            }

            int imageWidth = 0;
            int imageHeight = 0;
            int pageWidth = 0;
            int pageHeight = 0;

            e.Graphics.PageUnit = GraphicsUnit.Pixel;
            pageWidth = (int)(pageBounds.Width * e.Graphics.DpiX / 100) - leftMarginWidth;
            pageHeight = (int)(pageBounds.Height * e.Graphics.DpiY / 100) - topMargin;

            int horizSpacer = 10;// (pageWidth - totalWidth - leftMarginWidth) / m_imageCols;
            int vertSpacer = 10;//(pageHeight - totalHeight - topMargin) / m_imageRows;

            if (m_printSize == Size.Empty)
            {
                imageWidth = ((pageWidth - (horizSpacer * (m_imageCols / 2))) / m_imageCols);
                imageHeight = ((pageHeight - (vertSpacer * (m_imageRows / 2))) / m_imageRows);
            }
            else
            {
                imageWidth = (int)(m_printSize.Width * e.Graphics.DpiX);
                imageHeight = (int)(m_printSize.Height * e.Graphics.DpiY);
            }

            int maxWidth = 0;
            int maxHeight = 0;
            foreach (IImageData imageData in imagesToPrint)
            {
                int H = 0;
                int W = 0;
                if (imageData.ImageSize.Width < imageData.ImageSize.Height)
                {
                    H = imageData.ImageSize.Width;
                    W = imageData.ImageSize.Height;
                }
                else
                {
                    W = imageData.ImageSize.Width;
                    H = imageData.ImageSize.Height;
                }

                Size size = ImageAlgo.GetImageProportionalSize(new SizeF(W, H), new SizeF(imageWidth, imageHeight));
                maxWidth = Math.Max(size.Width, maxWidth);
                maxHeight = Math.Max(size.Height, maxHeight);
            }

            int totalWidth = maxWidth * m_imageCols;
            int totalHeight = maxHeight * m_imageRows;
            //int horizSpacer = (pageWidth - totalWidth - leftMarginWidth) / m_imageCols;
            //int vertSpacer = (pageHeight - totalHeight - topMargin) / m_imageRows;

            int X = ((pageWidth - totalWidth) / 2) + leftMarginWidth;
            int Y = ((pageHeight - totalHeight) / 2) + topMargin;
            int oldRow = 0;
            for (int ii = 0; ii < imagesToPrint.Length; ii++)
            {
                IImageData imageData = imagesToPrint[ii];
                
                Image image = null;
                if (m_printAction == PrintAction.PrintToPreview)
                {
                    image = new Bitmap(imageData.Thumbnail);
                }
                else
                {
                    image = imageData.FormatProvider.LoadImage(imageData);
                }

                using (image)
                {
                    if (image == null)
                    {
                        continue;
                    }

                    if (image.Width < image.Height)
                    {
                        image.RotateFlip(RotateFlipType.Rotate90FlipNone);
                    }

                    int row = ii / m_imageCols;
                    int col = (m_imageCols - ((m_imageCols * (row + 1)) - ii));
                    if (oldRow != row)
                    {
                        int height = 0;
                        for (int prevImages = ii - m_imageCols; prevImages < ii; prevImages++)
                        {
                            SizeF imageSize = new SizeF(imagesToPrint[prevImages].ImageSize.Width, imagesToPrint[prevImages].ImageSize.Height);
                            if (imageSize.Width < imageSize.Height)
                            {
                                imageSize = new SizeF(imageSize.Height, imageSize.Width);
                            }

                            Size prevImageSize = ImageAlgo.GetImageProportionalSize(imageSize, new SizeF(imageWidth, imageHeight));
                            height = Math.Max(height, prevImageSize.Height);
                        }

                        Y += height + vertSpacer;

                        oldRow = row;
                    }

                    if (col == 0)
                    {
                        X = ((pageWidth - totalWidth) / 2) + leftMarginWidth;
                    }
                    else
                        if (m_imageCols > 1)
                        {
                            SizeF imageSize = new SizeF(imagesToPrint[ii - 1].ImageSize.Width, imagesToPrint[ii - 1].ImageSize.Height);
                            if (imageSize.Width < imageSize.Height)
                            {
                                imageSize = new SizeF(imageSize.Height, imageSize.Width);
                            }

                            Size prevImageSize = ImageAlgo.GetImageProportionalSize(imageSize, new SizeF(imageWidth, imageHeight));
                            X += prevImageSize.Width + horizSpacer;
                        }

                    Size oneImageSize = ImageAlgo.GetImageProportionalSize(new SizeF(image.Width, image.Height), new SizeF(imageWidth, imageHeight));

                    Rectangle borderRect = new Rectangle();
                    Rectangle imageRect = new Rectangle();

                    borderRect.X = X;
                    borderRect.Y = Y;
                    borderRect.Width = oneImageSize.Width;
                    borderRect.Height = oneImageSize.Height;

                    imageRect = borderRect;

                    using (e.Graphics.Clip = new Region(Rectangle.Inflate(borderRect, -1, -1)))
                    {
                        using (Image printedImage = new Bitmap(imageRect.Size.Width, imageRect.Size.Height, e.Graphics))
                        {
                            using (Graphics g = Graphics.FromImage(printedImage))
                            {
                                g.PageUnit = e.Graphics.PageUnit;
                              //  Logger.Log("1- width = " + imageRect.Width.ToString() + " height = " + imageRect.Height.ToString());
                                g.DrawImage(image, 0, 0, imageRect.Width, imageRect.Height);
                             //   Logger.Log("2- width = " + imageRect.Width.ToString() + " height = " + imageRect.Height.ToString());
                                
                            }

                          //  Logger.Log("3- width = " + imageRect.Width.ToString() + " height = " + imageRect.Height.ToString());
                            e.Graphics.DrawImageUnscaled(printedImage, imageRect);
                        }
                    }

                    using (e.Graphics.Clip = new Region(Rectangle.Inflate(borderRect, 1, 1)))
                    {
                        e.Graphics.DrawRectangle(Pens.Black, borderRect);
                    }
                }
            }

            if (m_images.Count > m_nextImage)
            {
                e.HasMorePages = (m_printAction == PrintAction.PrintToPreview) ? false : true;
            }
            else
            {
                e.HasMorePages = false;
            }
        }
    }
}
